/**
 * Ingenius-Group S.A.S
 *
 * Project: SAU
 * File: AbstractListView.java
 * Date: 06/02/2011
 */

package com.ingenius.sau.client.view;

import java.util.List;

import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.data.BaseFilterPagingLoadConfig;
import com.extjs.gxt.ui.client.data.BasePagingLoadConfig;
import com.extjs.gxt.ui.client.data.BasePagingLoader;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelReader;
import com.extjs.gxt.ui.client.data.ModelData;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.extjs.gxt.ui.client.data.PagingLoader;
import com.extjs.gxt.ui.client.data.RpcProxy;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Info;
import com.extjs.gxt.ui.client.widget.InfoConfig;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.layout.ColumnLayout;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.FlowData;
import com.extjs.gxt.ui.client.widget.layout.FlowLayout;
import com.extjs.gxt.ui.client.widget.toolbar.PagingToolBar;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Widget;
import com.ingenius.sau.client.AppController;
import com.ingenius.sau.client.Callback;
import com.ingenius.sau.client.Constants;
import com.ingenius.sau.client.presenter.ListPresenter;
import com.ingenius.sau.client.presenter.Presenter;
import com.ingenius.sau.shared.util.filter.Filter;

/**
 * Class <strong>AbstractListView</strong>
 * 
 * @author Jesus David
 * @version 0.1
 */
public abstract class AbstractListView<Bean> extends LayoutContainer implements
		Display {

	// Data

	protected PagingLoader<PagingLoadResult<ModelData>> loader;

	protected ListPresenter<Bean> presenter;

	protected List<Filter> filters;

	protected int offset;

	protected int pageSize;

	// UI Widget

	protected final Button addButton;

	protected final Button editButton;

	protected final Button deleteButton;

	protected final ContentPanel gridContainer;

	protected final ContentPanel submenuContainer;

	protected final ContentPanel headerContainer;

	// Constructor

	public AbstractListView() {
		this(15);
	}

	public AbstractListView(int pageSize) {
		this.offset = 0;
		this.pageSize = pageSize;
		gridContainer = new ContentPanel();
		submenuContainer = new ContentPanel();
		headerContainer = new ContentPanel();

		// TDOD i18n
		addButton = new Button("Add");
		addButton.setIconStyle("icon-add");

		editButton = new Button("Edit");
		editButton.setIconStyle("icon-edit");

		deleteButton = new Button("Delete");
		deleteButton.setIconStyle("icon-delete");
	}

	// Methods

	protected abstract ColumnModel createColumnModel();

	protected abstract Widget createAdvancedSearch();

	@Override
	protected void onRender(Element parent, int index) {
		super.onRender(parent, index);
		enableButtons(false);

		if (presenter == null) {
			System.out.println("Presenter is null...");
			return;
		}

		gridContainer.setBodyBorder(true);
		gridContainer.setButtonAlign(HorizontalAlignment.CENTER);
		gridContainer.setLayout(new FitLayout());
		gridContainer.setSize(800, 500);

		gridContainer.add(createGrid());
		gridContainer.setBottomComponent(createPagingToolBar());

		gridContainer.addButton(addButton);
		gridContainer.addButton(editButton);
		gridContainer.addButton(deleteButton);

		LayoutContainer center = new LayoutContainer();
		center.setLayout(new FlowLayout(10));
		center.getAriaSupport().setPresentation(false);
		center.add(createAdvancedSearch(), new FlowData(10));
		center.add(gridContainer, new FlowData(10));

		submenuContainer.setFrame(false);
		submenuContainer.setHeaderVisible(false);
		submenuContainer.setBodyBorder(false);
		submenuContainer.setLayout(new FlowLayout(7));
		submenuContainer.setWidth(93);

		LayoutContainer left = new LayoutContainer();
		left.setLayout(new FlowLayout(10));
		left.add(submenuContainer);

		headerContainer.setFrame(false);
		headerContainer.setHeaderVisible(false);
		headerContainer.setBodyBorder(false);
		headerContainer.setLayout(new FlowLayout(0));
		headerContainer.setSize(930, 45);

		LayoutContainer top = new LayoutContainer();
		top.setLayout(new FlowLayout(7));
		top.add(headerContainer);

		LayoutContainer tmp = new LayoutContainer();
		tmp.setLayout(new ColumnLayout());
		tmp.add(left);
		tmp.add(center);

		LayoutContainer main = new LayoutContainer();
		main.setLayout(new FlowLayout(0));
		main.add(top);
		main.add(tmp);

		add(main);
		registerButtonsListeners();
	}

	protected Grid<BeanModel> createGrid() {
		ListStore<BeanModel> store = createListStore();
		ColumnModel columnModel = createColumnModel();

		Grid<BeanModel> grid = new Grid<BeanModel>(store, columnModel);
		grid.setLoadMask(true);
		grid.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
		grid.getSelectionModel().addListener(Events.SelectionChange,
				new Listener<SelectionChangedEvent<BeanModel>>() {
					public void handleEvent(SelectionChangedEvent<BeanModel> be) {
						String id = null;
						if (be.getSelection().size() > 0) {
							BeanModel bean = be.getSelection().get(0);
							id = bean.get("id").toString();
						}
						presenter.setSelectedItemId(id);

						if (id != null) {
							enableButtons(true);

						} else {
							enableButtons(false);
						}
					}
				});

		grid.addListener(Events.CellDoubleClick, new Listener<BaseEvent>() {
			public void handleEvent(BaseEvent be) {
				presenter.doEdit();
			}
		});

		grid.addListener(Events.Attach, new Listener<BaseEvent>() {
			public void handleEvent(BaseEvent be) {
				loader.load(offset, pageSize);
			}
		});

		grid.getView().setForceFit(true);
		grid.setAutoExpandColumn("description");
		grid.setStyleAttribute("borderTop", "none");
		grid.setBorders(false);
		grid.setStripeRows(true);
		grid.setColumnLines(true);

		return grid;
	}

	protected ListStore<BeanModel> createListStore() {
		RpcProxy<PagingLoadResult<Bean>> proxy = new RpcProxy<PagingLoadResult<Bean>>() {
			@Override
			public void load(Object loadConfig,
					AsyncCallback<PagingLoadResult<Bean>> callback) {

				offset = ((BasePagingLoadConfig) loadConfig).getOffset();
				presenter.loadData(filters, loadConfig, callback);
			}
		};

		BeanModelReader reader = new BeanModelReader();

		loader = new BasePagingLoader<PagingLoadResult<ModelData>>(proxy,
				reader) {
			@Override
			protected Object newLoadConfig() {
				BasePagingLoadConfig config = new BaseFilterPagingLoadConfig();
				return config;
			}
		};
		loader.setRemoteSort(true);

		return new ListStore<BeanModel>(loader);
	}

	protected void enableButtons(Boolean state) {
		deleteButton.setEnabled(state);
		editButton.setEnabled(state);
	}

	protected PagingToolBar createPagingToolBar() {
		PagingToolBar toolBar = new PagingToolBar(pageSize);
		toolBar.bind(loader);
		return toolBar;
	}

	protected void registerButtonsListeners() {
		addButton.addListener(Events.OnClick, new Listener<BaseEvent>() {
			@Override
			public void handleEvent(BaseEvent be) {
				presenter.doAdd();
			}
		});

		deleteButton.addListener(Events.OnClick, new Listener<BaseEvent>() {
			@Override
			public void handleEvent(BaseEvent be) {
				Callback callback = new Callback() {
					@Override
					public void excecute() {
						showConfirmDialog();
					}
				};
				AppController.doWhitPermission(presenter.getModuleName(),
						Constants.ACTION_DELETE, callback);
			}
		});

		editButton.addListener(Events.OnClick, new Listener<BaseEvent>() {
			@Override
			public void handleEvent(BaseEvent be) {
				presenter.doEdit();
			}
		});
	}

	private void showConfirmDialog() {
		MessageBox box = new MessageBox();
		box.setIcon(MessageBox.QUESTION);
		box.setButtons(MessageBox.YESNOCANCEL);
		final Button yesButton = (Button) box.getDialog().getButtonBar()
				.getItem(0);
		final Button noButton = (Button) box.getDialog().getButtonBar()
				.getItem(1);
		final Button cancelButton = (Button) box.getDialog().getButtonBar()
				.getItem(2);

		// TODO i18n
		box.setTitle("Delete Item?");
		box.setMessage("Are you sure you want to delete the selected item?");
		yesButton.setText("Yes");
		noButton.setText("No");
		cancelButton.setText("Cancel");

		box.addCallback(new Listener<MessageBoxEvent>() {
			@Override
			public void handleEvent(MessageBoxEvent be) {
				if (yesButton == be.getButtonClicked()) {
					presenter.doDelete();
				}
			}
		});
		box.show();
	}

	public void reload() {
		loader.load();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ingenius.sau.client.mvp.views.Display#showInfo(java.lang.String)
	 */
	@Override
	public void showInfo(String msg) {
		InfoConfig config = new InfoConfig("Info", msg);
		Info info = new Info();
		info.setAnimCollapse(true);
		info.setBodyStyleName("info-style");
		info.show(config);

		int left = info.getAbsoluteLeft() - 15;
		int top = info.getAbsoluteTop() - 15;
		info.setPosition(left, top);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.ingenius.sau.client.mvp.views.Display#setPresenter(com.ingenius.sau
	 * .client.mvp.presenters.Presenter)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void setPresenter(Presenter presenter) {
		this.presenter = (ListPresenter<Bean>) presenter;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.ingenius.sau.client.mvp.views.Display#asWidget()
	 */
	@Override
	public Widget asWidget() {
		return this;
	}
}
